package com.lt.flashcard.view;

/**
 * Controller for create flashcard page
 * @version 1.0
 * @author Nguyen Trung Tam
 *
 */
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.bson.types.ObjectId;
import org.json.JSONArray;
import org.zkoss.bind.BindUtils;
import org.zkoss.bind.GlobalCommandEvent;
import org.zkoss.image.AImage;
import org.zkoss.util.media.Media;
import org.zkoss.xel.fn.StringFns;
import org.zkoss.zhtml.Li;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.InputEvent;
import org.zkoss.zk.ui.event.UploadEvent;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zkex.util.Base64Coder;
import org.zkoss.zkmax.ui.select.annotation.Subscribe;
import org.zkoss.zul.A;
import org.zkoss.zul.Div;
import org.zkoss.zul.Image;
import org.zkoss.zul.Label;
import org.zkoss.zul.Radiogroup;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Window;

import com.lt.flashcard.Utility;
import com.lt.flashcard.model.entity.Flashcard;
import com.lt.flashcard.model.entity.FlashcardSet;
import com.lt.flashcard.model.entity.Tag;
import com.lt.flashcard.model.entity.User;
import com.lt.flashcard.model.service.AAService;
import com.lt.flashcard.model.service.FlashcardService;
import com.lt.flashcard.model.service.FlashcardSetService;
import com.lt.flashcard.model.service.Repository;
import com.lt.flashcard.model.service.TagService;
import com.lt.flashcard.model.service.UserService;
import com.mongodb.gridfs.GridFS;

public class FlashcardCtrl extends SelectorComposer<Component> {

    private static final Logger log = Logger.getLogger(FlashcardCtrl.class);
    private static final long serialVersionUID = 1L;

    private FlashcardSet flashcardSet = new FlashcardSet();
    private List<Long> fcIds = new ArrayList<Long>();
    private Flashcard flashcard = null;
    private static final String SAVE_PATH = Utility.getConfiguration("com.lt.flashcard.audioStreamFolder", Utility.getWebAppPath() + "sound\\");// Utility.getWebAppPath()
                                                                                                                                                // + "sound\\";
    private User user;

    @Wire
    Textbox setName;
    @Wire
    Textbox setDescription;
    @Wire
    Image setImage;
    @Wire
    Textbox fTerm;
    @Wire
    Textbox fNotes;
    @Wire
    Image fImage;
    @Wire
    Textbox fDefinition;
    @Wire
    Textbox soundFront;
    @Wire
    Textbox soundBack;
    @Wire
    Li _flashcard;
    @Wire
    Div abc;
    @Wire
    Radiogroup privacy;
    @Wire
    Textbox finalTag; // Store the tags
    @Wire
    Textbox fnAllowedUsers;
    @Wire
    Textbox fnDeniedUsers;
    @Wire
    Textbox doodleData;
    @Wire
    Label notifyEdit;
    @Wire
    A linkCancelMulti;
    @Wire
    Label numberBlankFC;

    @Override
    public void doBeforeComposeChildren(Component comp) throws Exception {
        try {
            String task = Executions.getCurrent().getParameter("task");
            String Id = Executions.getCurrent().getParameter("id");
            String strFcIds = Executions.getCurrent().getParameter("fcids");
            if (task != null && task.equals("edit") && StringUtils.isNotBlank(Id)) {
                Long lId = new Long(Id);
                FlashcardSetService fsSrv = Repository.getInstance().getFlashcardSetService();
                flashcardSet = fsSrv.findByID(lId);
                if (flashcardSet == null) {
                    Utility.display404(true);
                    return;
                }

                if (strFcIds != null) {
                    String[] arrFcIds = strFcIds.split(",");
                    for (String sfcId : arrFcIds) {
                        Long fcId = Long.parseLong(sfcId);
                        fcIds.add(fcId);
                    }
                    flashcard = flashcardSet.getFlashcardById(fcIds.get(0));
                    fcIds.remove(0);
                }
            }
            // getFlashcard();

            // Check permission
            AAService asrv = Repository.getInstance().getAAService();
            this.user = asrv.getCurrentUser();
            if (!asrv.checkEdit(user, flashcardSet)) {
                Utility.loginOrAccessDenied(false);
                return;
            }
            super.doBeforeComposeChildren(comp);
        } catch (Exception e) {
            e.printStackTrace();
            Utility.display404(true);
            return;
        }
    }

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        if (flashcardSet != null && StringUtils.isNotBlank(flashcardSet.getImage())) {
            setImage.setSrc(Utility.loadImageFromGridFS(flashcardSet.getImage(), ""));
        } else {
            setImage.setSrc("images/def_fcs.png");
        }
        fImage.setSrc("");

        renderNotifyEdit();
        if (flashcard != null) {
            updateFlashcardValue();
        } else {
            Clients.evalJavaScript("$('.fterm').val('Từ chính');" + "$('.fnotes').val('(Phiên âm câu ví dụ...)');"
                    + "$('.flistname').val('Chủ đề');" + "$('.fdefinition').val('định nghĩa');" + "$('.tdimage').hide(); "
                    + "$('.tddefinition').css({height:'200px', width: '100%', 'text-align': 'center', 'vertical-align': 'middle'});"
                    + "$('.fdefinition').css({width: '430px', 'margin-left': '10px'});");
        }
        String notify = Executions.getCurrent().getParameter("notify");
        if (notify != null) {
            Clients.evalJavaScript("$.showNotice('','Một số flashcard trùng term với flashcard set bạn chọn: " + notify + "');");
        }
    }

    // ----------------setter and getter-------

    public void setFlashcard(Flashcard flashcard) {
        this.flashcard = flashcard;
    }

    public Flashcard getFlashcard() {
        if (flashcard == null) {
            flashcard = new Flashcard();
        }
        return flashcard;
    }

    public void setFlashcardSet(FlashcardSet flashcardSet) {
        this.flashcardSet = flashcardSet;
    }

    public FlashcardSet getFlashcardSet() {
        if (flashcardSet == null) {
            flashcardSet = new FlashcardSet();
        }
        return flashcardSet;
    }

    public void setFcIds(List<Long> fcIds) {
        this.fcIds = fcIds;
    }

    public List<Long> getFcIds() {
        return this.fcIds;
    }

    // ----------------end setter and getter------------------

    // --------------methods---------------------------
    /**
     * 
     *Update properties 's current flashcard set
     */
    private void updateFlashcardSet(String name, int privacy, String description, User user) {
        flashcardSet.setName(name);
        flashcardSet.setPrivacy(privacy);
        flashcardSet.setDescription(description);
        flashcardSet.setAuthor(user);
    }

    /**
     * Update tag for current flashcard set
     */
    public void updateTag() {
        String strTags = finalTag.getValue();
        if (strTags.length() > 0) {
            String[] arrTags = strTags.split(",");

            Set<String> arrFilter = new HashSet<String>();

            for (String tag : arrTags) {
                if (tag.length() < 4) {
                    continue;
                }
                arrFilter.add(tag.substring(0, tag.length() - 2).trim());
            }

            TagService srv = Repository.getInstance().getTagService();
            Set<String> arrAvTags = new HashSet<String>();
            List<Tag> listTags = srv.getTagByName(arrFilter);
            for (Tag tag : listTags) {
                arrAvTags.add(tag.getName());
            }

            for (String tag : arrFilter) {
                if (arrAvTags.contains(tag)) {
                    continue;
                }

                Tag newTag = new Tag();
                newTag.setName(tag);
                try {
                    srv.save(newTag);
                } catch (Exception e) {
                    log.error(String.format("Can't save tag: %s, flashcardsetid: %s", tag, flashcardSet.getId()), e);
                    newTag = srv.findTagByName(tag);
                }
                if (newTag != null) {
                    listTags.add(newTag);
                }
            }

            Set<Tag> set = new HashSet<Tag>(listTags);
            flashcardSet.setTags(set);
        }
    }

    /**
     * render notify
     */
    protected void renderNotifyEdit() {
        if (fcIds != null && fcIds.size() > 0) {
            notifyEdit.setSclass("editmore");
            linkCancelMulti.setVisible(true);
            notifyEdit.setValue(String.format("Còn edit %d card", fcIds.size()));
        } else {
            notifyEdit.setSclass("");
            notifyEdit.setValue("");
            linkCancelMulti.setVisible(false);
        }
    }

    /**
     * display value of flashcard at website
     * @throws IOException 
     */
    protected void updateFlashcardValue() throws IOException {
        fDefinition.setValue(flashcard.getDefinition());
        fNotes.setValue(flashcard.getNotes());
        if (flashcard.getNotes().length() == 0) {
            Clients.evalJavaScript("$('.fnotes').val('(Phiên âm câu ví dụ...)');");
        }
        fImage.setSrc(Utility.loadImageFromGridFS(flashcard.getImage(), ""));
        if (flashcard.getImage().length() > 0) {
            Clients.evalJavaScript("$('.tdimage').show();" + "$('.fdefinition').css({width: '210px', 'margin-left': '0px'});");
        } else {
            Clients.evalJavaScript("$('.tdimage').hide(); "
                    + "$('.tddefinition').css({height:'200px', width: '100%', 'text-align': 'center', 'vertical-align': 'middle'});"
                    + "$('.fdefinition').css({width: '430px', 'margin-left': '10px'});");
        }
        fTerm.setValue(flashcard.getTerm());
        soundFront.setValue(flashcard.getSoundFront());
        soundBack.setValue(flashcard.getSoundFront());
    }

    /**
     * save new flashcard set
     */
    @Listen("onClick=#saveFlashcardSet")
    public void saveSet() {
        int privacy = new Integer(this.privacy.getSelectedItem().getValue().toString());
        String name = setName.getValue().trim();
        String description = setDescription.getValue().trim();

        updateFlashcardSet(name, privacy, description, this.user);
        FlashcardSetService fsSrv = Repository.getInstance().getFlashcardSetService();
        updateTag();
        // flashcardSet.setTestingresultCache("");
        if (fsSrv.save(flashcardSet)) {
            Clients.evalJavaScript("$.removeBeforeUnload();");
            Utility.rawRedirect(Utility.removeContextPath(Utility.generateUrl("flashcardset", flashcardSet.getId(), flashcardSet.getName())), true);
        } else {
            Clients.evalJavaScript("showNotice('', 'Không thể lưu bộ từ. Bạn hãy kiểm tra lại.');");
        }
    }

    /**
     * check white_flashcard
     */
    public boolean hasWhiteFlashcard() {
        return user.getCurrentblankflashcard() > 0 ? true : false;
    }

    /**
     * Not edit multi cards anymore
     */
    @Listen("onClick=#linkCancelMulti")
    public void linkCancelMulti() {
        flashcard = new Flashcard();
        fTerm.setValue("");
        fNotes.setValue("");
        fDefinition.setValue("");
        fImage.setSrc("");
        soundFront.setValue("");
        soundBack.setValue("");
        Clients.evalJavaScript("$('.fterm').val('Từ chính'); " + "$('.fnotes').val('(Phiên âm câu ví dụ...)'); "
                + "$('.flistname').val('Chủ đề'); " + "$('.fdefinition').val('định nghĩa');" + "$('.tdimage').hide(); "
                + "$('.tddefinition').css({height:'200px', width: '100%', 'text-align': 'center', 'vertical-align': 'middle'});"
                + "$('.fdefinition').css({width: '430px', 'margin-left': '10px'});");
        fcIds.clear();
        renderNotifyEdit();
    }

    /**
     * save new flashcard or edit flashcard if flashcard exist
     * update flashcard list detail
     * create new flashcard after save or edit flashcard
     * @throws IOException 
     */
    @Listen("onClick=#saveFlashcard")
    public void saveAndEditFlashcard() throws IOException {
        String flashcardTerm = fTerm.getValue().trim();
        String flashcardNotes = fNotes.getValue().trim();
        String flashcardDefinition = fDefinition.getValue().trim();
        String flashcardSoundFront = soundFront.getValue();
        String flashcardSoundBack = soundBack.getValue();
        // Check white flashcard
        if (!hasWhiteFlashcard()) {
            Clients.evalJavaScript("showNotice('', 'Bạn không đủ flashcard trắng. Hãy mua thêm!');");// no
            return;
        }
        // Check required field for flashcard
        if (flashcardTerm.length() == 0 || (flashcardDefinition.length() == 0 && fImage.getContent() == null)) {
            String msg = "";
            if (flashcardTerm.length() == 0) {
                msg = "Flashcard chưa có từ";
            } else {
                msg = "Flashcard phải có hình ảnh hoặc định nghĩa";
            }
            Clients.evalJavaScript("showNotice('','" + msg + "');");
            return;
        }
        // Check dupplicate term
        if (flashcardSet.isTermExist(flashcardTerm) && (flashcard == null || !flashcard.getTerm().equals(flashcardTerm))) {
            Clients.evalJavaScript("showNotice('','Từ này đã có rồi');");
            return;
        }

        FlashcardSetService fsSrv = Repository.getInstance().getFlashcardSetService();
        FlashcardService fSrv = Repository.getInstance().getFlashcardService();

        // save flashcard in case edit
        if (flashcard != null && flashcard.getId() != null) {
            flashcard.setTerm(flashcardTerm);
            flashcard.setNotes(flashcardNotes);
            flashcard.setDefinition(flashcardDefinition);
            flashcard.setSoundFront(flashcardSoundFront);
            flashcard.setSoundBack(flashcardSoundBack);
            if (!fSrv.save(flashcard)) {
                Clients.evalJavaScript("showNotice('', 'Không thể lưu flashcard. Bạn hãy kiểm tra lại.')");
                return;
            }
        } else {// save flashcard in case new
            boolean isNew = false;

            // save flashcardset first
            if (flashcardSet.getId() == null) {
                isNew = true;
                int privacy = new Integer(this.privacy.getSelectedItem().getValue().toString());
                String name = setName.getValue();
                String description = setDescription.getValue();

                if (Utility.isEmptyString(name)) {
                    Clients.evalJavaScript("showNotice('', 'Bạn hãy nhập tên cho bộ từ');");
                    return;
                }

                updateFlashcardSet(name, privacy, description, this.user);
            }

            if (flashcard == null) {
                flashcard = new Flashcard();
            } else if (flashcard.getId() != null) {
            }

            flashcardSet.setDraft(FlashcardSet.SET_APPROVED);
            fSrv.updateFlashcard(flashcard, flashcardTerm, flashcardNotes, flashcardDefinition, flashcardSoundFront, flashcardSoundBack, flashcardSet);
            flashcardSet.addFlashcard(flashcard);
            // numberBlankFC.setValue(String.valueOf(currentblankflashcard));
            // fsSrv.updateTotalFlashcards(flashcardSet);

            if (isNew) {
                updateTag();
                if (!fsSrv.save(flashcardSet)) {
                    Clients.evalJavaScript("showNotice('', 'Không thể lưu bộ từ. Bạn hãy kiểm tra lại');");
                    return;
                }
                Clients.evalJavaScript("$.removeBeforeUnload();");
                Executions.sendRedirect("/flashcard.zul?task=edit&id=" + flashcardSet.getId());
                return;
            } else {
                if (!fsSrv.save(flashcardSet)) {
                    Clients.evalJavaScript("showNotice('', 'Không thể lưu bộ từ. Bạn hãy kiểm tra lại');");
                    return;
                }
            }
        }

        // update flashcard list detail
        Map<String, Object> arg = new HashMap<String, Object>();
        arg.put("flashcardSet", flashcardSet);
        BindUtils.postGlobalCommand(null, null, "updateFlashcardList", arg);

        // after flashcard saved, create new flashcard or display next flashcard in list flashcard edited
        // take flashcard has edited out list flashcard edited
        if (fcIds != null && fcIds.size() > 0) {
            flashcard = flashcardSet.getFlashcardById(fcIds.get(0));
            fcIds.remove(0);
            updateFlashcardValue();
            renderNotifyEdit();
        } else {
            flashcard = new Flashcard();
            fTerm.setValue("");
            fNotes.setValue("");
            fDefinition.setValue("");
            fImage.setSrc("");
            soundFront.setValue("");
            soundBack.setValue("");
            Clients.evalJavaScript("$('.fterm').val('Từ chính'); " + "$('.fnotes').val('(Phiên âm câu ví dụ...)'); "
                    + "$('.flistname').val('Chủ đề'); " + "$('.fdefinition').val('định nghĩa');" + "$('.tdimage').hide(); "
                    + "$('.tddefinition').css({height:'200px', width: '100%', 'text-align': 'center', 'vertical-align': 'middle'});"
                    + "$('.fdefinition').css({width: '430px', 'margin-left': '10px'});");
            notifyEdit.setValue("");
        }
    }

    /**
     * invoke modal to upload image flashcardset 
     * pass type=fs to upload image flashcardset or type=f to upload image flashcard
     * pass fOrFs = flashcardSet to reference to flashcardSet, fOrFs = flashcard to reference to flashcard
     * @throws IOException
     */

    @Listen("onUpload=#uploadImageSet")
    public void uploadImageSet(UploadEvent event) throws IOException {
        org.zkoss.util.media.Media media = event.getMedia();
        if (media instanceof org.zkoss.image.Image) {
            int h = ((org.zkoss.image.Image) media).getHeight();
            int w = ((org.zkoss.image.Image) media).getWidth();
            if (w < 140 || h < 140) {
                Clients.evalJavaScript("showNotice('', 'Kích thước ảnh nhỏ nhất 140x140')");
            } else {
                if (h >= w) {
                    w = w * 385 / h;
                    h = 385;
                } else if (h <= w) {
                    h = h * 385 / w;
                    w = 385;
                }
                InputStream in = media.getStreamData();
                AImage img = new org.zkoss.image.AImage("", in);
                // invoke modal upload imageset

                Object type = "fs";
                final Map<String, Object> args = new HashMap<String, Object>();
                args.put("fOrFs", flashcardSet);
                args.put("key", type);
                args.put("img", img);
                args.put("w", w);
                args.put("h", h);
                Window window = (Window) Executions.createComponents("/modal/flashcardModalUploadImage.zul", null, args);
                window.doModal();
                window.setPosition("center,center");

            }

        } else {
            Clients.evalJavaScript("showNotice('', 'Không phải ảnh')");
        }
    }

    @Listen("onUpload=#uploadImageFlashcard")
    public void uploadImageFlashcard(UploadEvent event) throws IOException {
        org.zkoss.util.media.Media media = event.getMedia();
        if (media instanceof org.zkoss.image.Image) {
            int h = ((org.zkoss.image.Image) media).getHeight();
            int w = ((org.zkoss.image.Image) media).getWidth();
            if (w < 230 || h < 135) {
                Clients.evalJavaScript("showNotice('', 'Kích thước tối thiểu: 230x135px. Vui lòng làm lại.')");
            } else {
                if (h >= w) {
                    w = w * 385 / h;
                    h = 385;
                } else if (h <= w) {
                    h = h * 385 / w;
                    w = 385;
                }
                InputStream in = media.getStreamData();
                AImage img = new org.zkoss.image.AImage("", in);
                // invoke modal upload imageset
                Object type = "f";
                final Map<String, Object> args = new HashMap<String, Object>();
                getFlashcard();
                args.put("fOrFs", flashcard);
                args.put("key", type);
                args.put("img", img);
                args.put("w", w);
                args.put("h", h);
                Window window = (Window) Executions.createComponents("/modal/flashcardModalUploadImage.zul", null, args);
                window.doModal();
            }

        } else {
            Clients.evalJavaScript("showNotice('', 'Hình không hợp lệ')");
        }
    }

    @Subscribe("fCoS")
    public void refreshvalues(Event evt) throws IOException {
        if (evt instanceof GlobalCommandEvent) {
            Map<String, Object> args = ((GlobalCommandEvent) evt).getArgs();
            // for upload image flashcardSet
            if ("refreshvaluesSet".equals(((GlobalCommandEvent) evt).getCommand())) {
                flashcardSet = (FlashcardSet) args.get("flashcardset");
                setImage.setSrc(Utility.loadImageFromGridFS(flashcardSet.getImage(), ""));// change it
            }
            // for upload image flashcard
            if ("refreshvaluesFC".equals(((GlobalCommandEvent) evt).getCommand())) {
                flashcard = (Flashcard) args.get("flashcard");
                fImage.setSrc(Utility.loadImageFromGridFS(flashcard.getImage(), ""));// change it
                Clients.evalJavaScript("$.onUpdateFlashcardImage()");
            }
        }
    }

    /**
     * invoke dochange() at V_flashcard_list to include list flashcard exist when fTerm text change
     */
    @Listen("onChanging=#fTerm")
    public void doChange(InputEvent event) {
        Map<String, Object> args = new HashMap<String, Object>();
        args.put("term", event.getValue());
        args.put("flashcardset", flashcardSet);
        BindUtils.postGlobalCommand(null, null, "doChange", args);
    }

    @Listen("onUpload=#uploadSoundFront")
    public void uploadSoundFront(UploadEvent event) throws IOException {
        getFlashcard();
        uploadSound(event, "front");
    }

    @Listen("onUpload=#uploadSoundBack")
    public void uploadSoundBack(UploadEvent event) throws IOException {
        getFlashcard();
        uploadSound(event, "back");
    }

    private void uploadSound(UploadEvent event, String position) throws IOException {
        Media media = event.getMedia();
        String[] filenames = media.getName().split("\\.");

        String type = media.getContentType().split("/")[0];// contenttype = "audio/mpeg"=> check audio

        if (filenames[filenames.length - 1].toLowerCase().equals("mp3")) {
            saveFile(media, position);
        } else {
            Clients.evalJavaScript("showNotice('', 'Không phải file mp3')");
        }
    }

    private void saveFile(Media media, String position) {
        BufferedInputStream in = null;
        BufferedOutputStream out = null;

        try {
            InputStream fin = media.getStreamData();
            in = new BufferedInputStream(fin);

            File baseDir = new File(SAVE_PATH);

            if (!baseDir.exists()) {
                baseDir.mkdirs();
            }
            String unique = unique();
            String[] filenames = media.getName().split("\\.");

            String fileName = media.getName().replaceAll("[^\\p{Alpha}\\p{Digit}]|mp3+", "") + unique + "." + filenames[filenames.length - 1];
            File file = new File(SAVE_PATH + fileName);

            OutputStream fout = new FileOutputStream(file);
            out = new BufferedOutputStream(fout);
            byte buffer[] = new byte[1024];
            int ch = in.read(buffer);
            while (ch != -1) {
                out.write(buffer, 0, ch);
                ch = in.read(buffer);
            }
            if (position.equals("front")) {
                soundFront.setValue(fileName);
                flashcard.setSoundFront(fileName);
            } else {
                soundBack.setValue(fileName);
                flashcard.setSoundBack(fileName);
            }
            Clients.evalJavaScript("showNotice('', 'Upload thành công')");
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }

                if (in != null) {
                    in.close();
                }

            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private String unique() {
        int min, max;
        min = 0;
        max = 1000;
        Random rd = new Random();
        int rand = rd.nextInt(max - min + 1) + min;
        java.util.Date date = new java.util.Date();
        String unique = Utility.formatDate(date, "yyMMddHHmmss") + String.valueOf(rand);
        return unique;
    }

    private List<Tag> tagList = null;

    /**
     * Get admin tags for chude
     * @return
     */
    public List<Tag> getAdmintags() {
        if (tagList == null) {
            tagList = Repository.getInstance().getTagService().getAdminTagList();
        }
        return tagList;
    }

    /**
     * Get all tags of system
     * TODO need optimize this
     * @return
     */
    public String getTags() {
        List<Tag> lst = Repository.getInstance().getTagService().getTagList();
        JSONArray result = new JSONArray();
        for (Tag tag : lst) {
            result.put(tag.getName());
        }
        return result.toString();
    }

    /*
     * delete image set
     */
    @Listen("onClick=#deleteImageSet")
    public void deleteImageSet() {
        if (flashcardSet.getImage().length() > 0) {
            try {
                // Utility.deleteImage(flashcardSet.getImage());
                setImage.setSrc(Utility.DEF_FLASHCARDSET);
                flashcardSet.setImage(null);
                FlashcardSetService fsSrv = Repository.getInstance().getFlashcardSetService();
                fsSrv.save(flashcardSet);
            } catch (Exception e) {
            }
        }
    }

    /*
     * delete image flashcard
     */
    @Listen("onClick=#deleteImageFlashcard")
    public void deleteImageFlashcard() {
        if (flashcard != null && StringUtils.isNotBlank(flashcard.getImage())) {
            try {
                GridFS fs = Repository.getInstance().getGridFS();
                fs.remove(new ObjectId(flashcard.getImage()));
                fImage.setSrc("");
                flashcard.setImage("");

                if (flashcard.getId() != null) {
                    FlashcardService fSrv = Repository.getInstance().getFlashcardService();
                    fSrv.save(flashcard);
                }
                Clients.evalJavaScript("$.onDeleteFlashcardImage()");
            } catch (Exception e) {
            }
        }
    }

    /*
     * cancel edit flashcardSet
     */
    @Listen("onClick=#cancelFlashcardSet")
    public void cancelFlashcardSet() {
        // delete the image in case of upload
        if (flashcardSet != null && flashcardSet.getId() == null && flashcardSet.getImage().length() > 0) {
            // delete the image
            // Repository.getInstance().deleteBinaryData(flashcardSet.getImage());
        }
        if (flashcardSet == null || flashcardSet.getId() == null) {
            Utility.redirect("wordlist.zul", true);
        } else {
            Utility.rawRedirect(Utility.removeContextPath(Utility.generateUrl("flashcardset", flashcardSet.getId(), flashcardSet.getName())), true);
        }
    }

    /**
     * Return string of username of friends of current user
     * @return
     */
    public String getFriends() {
        AAService asrv = Repository.getInstance().getAAService();
        UserService srv = Repository.getInstance().getUserService();
        List<String> usernames = new ArrayList<String>();
        for (User user : srv.getFriendList(asrv.getCurrentUser())) {
            usernames.add('"' + user.getUsername() + '"');
        }
        return StringFns.join(usernames.toArray(), ",");
    }

    /**
     * Get list of denied users
     * @return
     */
    public List<User> getDeniedUsers() {
        FlashcardSetService srv = Repository.getInstance().getFlashcardSetService();
        return srv.getDeniedUsers(flashcardSet);
    }

    /**
     * Get list of usernames of allowed users
     * @return
     */
    public List<User> getAllowedUsers() {
        FlashcardSetService srv = Repository.getInstance().getFlashcardSetService();
        return srv.getAllowedUsers(flashcardSet);
    }

    /*
     * save advance privacy
     */
    @Listen("onClick=#luu_riengtu")
    public void savePrivacy() {
        String strAllowedUsers = fnAllowedUsers.getValue();
        String allowedUsers = getAllowedAnDeniedUsers(strAllowedUsers);

        String strDeniedUsers = fnDeniedUsers.getValue();
        String deniedUsers = getAllowedAnDeniedUsers(strDeniedUsers);

        if (allowedUsers.length() > 0) {
            flashcardSet.setAllowedusersCache(allowedUsers);
        }
        if (deniedUsers.length() > 0) {
            flashcardSet.setDeniedusersCache(deniedUsers);
        }

        Clients.evalJavaScript("doClosePrivacyDialog();");
    }

    /*
     * get string Allowed or Denied Users
     */
    public String getAllowedAnDeniedUsers(String strUsers) {
        String[] arrAllowedUsers = strUsers.split(",");
        if (arrAllowedUsers.length > 0) {
            Set<String> arrFilter = new HashSet<String>();

            for (String user : arrAllowedUsers) {
                if (user.length() < 4) {
                    continue;
                }
                String userId = getId(user.substring(0, user.length() - 2));
                arrFilter.add(userId);
            }
            return StringFns.join(arrFilter.toArray(), ",");
        } else {
            return null;
        }
    }

    /*
     * get user id from username
     */
    public String getId(String username) {
        UserService srv = Repository.getInstance().getUserService();
        User tmpUser = srv.findByUsername(username);
        return tmpUser.getId().toString();
    }

    @Listen("onChange=#doodleData")
    public void onDoodleChange() {
        String data = doodleData.getValue().replace("data:image/png;base64,", "");
        doodleData.setValue("");
        try {
            AImage a = new AImage("", Base64Coder.decode(data.toCharArray()));
            String img = Utility.saveImage(a.getStreamData());
            fImage.setSrc(Utility.loadImageFromGridFS(img, ""));
            getFlashcard();
            flashcard.setImage(img);
            Clients.evalJavaScript("$.onUpdateFlashcardImage()");
        } catch (Exception e) {
            log.error("Can't save doodle", e);
        }
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}
